package com.klangner.math.transform;

import java.util.Vector;

import com.klangner.math.ast.Node;
import com.klangner.math.ast.NumericNode;
import com.klangner.math.ast.OperatorNode;

public class AddTransform extends BaseTransform {

	@Override
	public Node transformOperator(OperatorNode srcNode) {
		
		Node outputNode = srcNode;
		Vector<AddTerm> terms;
		
		terms = selectNodes(srcNode, false);
		// Simplify only if more then 1 node
		if(terms.size() > 1){
			// Looks for terms which coud be added
			int count = terms.size();
			for(int i = 0; i < terms.size(); i++){
				
				AddTerm term = terms.get(i);
				
				for(int j = i+1; j < terms.size(); ){
					AddTerm addTerm = term.add(terms.get(j)); 
					if( addTerm != null){
						term = addTerm;
						terms.set(i, addTerm);
						terms.remove(j);
					}
					else{
						j++;
					}
				}
			}
			
			// Check if we were ably to add any terms
			if(count > terms.size()){
				outputNode = mergeNodes(terms);
			}
		}
		
		
		return outputNode;
	}

	
	/**
	 * Find all nodes which can be added
	 * @param node
	 * @return array with terms
	 */
	private Vector<AddTerm> selectNodes(Node node, boolean negative){
		
		Vector<AddTerm> nodes = new Vector<AddTerm>();
		
		if( node instanceof OperatorNode )
		{
			Character op = node.getText().charAt(0);
			if( '+' == op || '-' == op ){
				if(node.getFirstChild() != null)
					nodes.addAll(selectNodes(node.getFirstChild(), negative));
				
				boolean n = negative;
				if('-' == op)
					n = !n;
				nodes.addAll(selectNodes(node.getSecondChild(), n));
			}
			else{
				nodes.add( new AddTerm(node, negative) );
			}
		}
		else {
			nodes.add( new AddTerm(node, negative) );
		}
		
		
		return nodes;
	}

	/**
	 * convert node list into node tree
	 * @param terms
	 * @return root node
	 */
	private Node mergeNodes(Vector<AddTerm> terms) {
		
		Node rootNode = null;
		
		for(AddTerm term : terms){
			
			Node node = term.getNode();
			if(null == rootNode){
				rootNode = node;
			}
			else{
				Node opNode;

				if( !(node instanceof NumericNode) ||
					!(node.getText().compareTo("0") == 0) )
				{
					if(term.isNegative())
						opNode = new OperatorNode("-");
					else
						opNode = new OperatorNode("+");
					opNode.setFirstChild(rootNode);
					opNode.setSecondChild(node);
					rootNode = opNode;
				}
			}
		}
		
		
		return rootNode;
	}


	
}
